/********************************************************************************************************
 * @file AdvScanFragment.java
 *
 * @brief for TLSR chips
 *
 * @author telink
 * @date Sep. 30, 2019
 *
 * @par Copyright (c) 2019, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
 *
 *          Licensed under the Apache License, Version 2.0 (the "License");
 *          you may not use this file except in compliance with the License.
 *          You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 *          Unless required by applicable law or agreed to in writing, software
 *          distributed under the License is distributed on an "AS IS" BASIS,
 *          WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *          See the License for the specific language governing permissions and
 *          limitations under the License.
 *******************************************************************************************************/
package com.telink.lt.ui;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.telink.lt.AdvertisingDevice;
import com.telink.lt.R;
import com.telink.lt.TelinkLog;
import com.telink.lt.adapter.AdvertisingDeviceListAdapter;
import com.telink.lt.adapter.BaseRecyclerViewAdapter;
import com.telink.ota.util.FileSystem;


public class AdvScanFragment extends BaseFragment implements BeaconRecordService.RecordChangeListener {

    private static final String FILTER_CACHE_NAME = "com.telink.ble.beacon.filter";

    private AdvertisingDeviceListAdapter beaconListAdapter;

    private final Handler mScanHandler = new Handler();
    private BluetoothAdapter mBluetoothAdapter;
    private final static long SCAN_PERIOD = 30 * 1000;
    private boolean mScanning = false;
    RecyclerView recyclerView;
    private ProgressBar pb_refreshing;
    private TextView tv_filter;
    private Toolbar toolbar;

    private RecordFilter recordFilter = new RecordFilter();

    private AlertDialog filterDialog;


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_device_list, null);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        recyclerView = view.findViewById(R.id.rv_list);
        final DividerItemDecoration decoration = new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL);
        recyclerView.addItemDecoration(decoration);

//        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        initFilter();
        BeaconRecordService.getInstance().init(this);
        BeaconRecordService.getInstance().syncFilter(recordFilter);
        initView(view);
        updateFilterText();
    }


    public void setBluetoothAdapter(BluetoothAdapter bluetoothAdapter) {
        this.mBluetoothAdapter = bluetoothAdapter;
    }

    /**
     * 过滤
     */
    private void initFilter() {
        RecordFilter filter = (RecordFilter) FileSystem.readAsObject(getActivity(), FILTER_CACHE_NAME);
        if (filter == null) {
            filter = new RecordFilter(-100, "");
        }
        this.recordFilter = filter;

    }

    private void initView(View view) {
        recyclerView = view.findViewById(R.id.rv_list);
        pb_refreshing = view.findViewById(R.id.pb_refreshing);
        tv_filter = view.findViewById(R.id.tv_filter);
        TextView tv_title = view.findViewById(R.id.tv_title);
        tv_title.setText(R.string.advertising_title);
        toolbar = view.findViewById(R.id.title_bar);
//        toolbar.inflateMenu(R.menu.menu_adv);
//        toolbar.getMenu().findItem(R.id.item_scan).setTitle(getAppVersion());
//        toolbar.getMenu().findItem(R.id.item_filter).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
//            @Override
//            public boolean onMenuItemClick(MenuItem item) {
//                showFilterDialog();
//                return false;
//            }
//        });
        toolbar.setNavigationIcon(R.drawable.ic_refresh);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                scanToggle(!mScanning);
            }
        });

        beaconListAdapter = new AdvertisingDeviceListAdapter(getActivity(), BeaconRecordService.getInstance().getDisplayRecords());

        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        recyclerView.setAdapter(beaconListAdapter);

        beaconListAdapter.setOnItemClickListener(new BaseRecyclerViewAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(int position) {
                if (mScanning) {
                    scanToggle(false);
                }
                TelinkLog.d("item click: " + position);
                BluetoothDevice bluetoothDevice = BeaconRecordService.getInstance().getDisplayRecords().get(position).device;
                startActivity(new Intent(getActivity(), OtaActivity.class)
                        .putExtra("device", bluetoothDevice));
            }
        });
        scanToggle(!mScanning);
    }

    private void scanToggle(final boolean enable) {
        mScanHandler.removeCallbacks(scanTask);
        if (enable) {
            TelinkLog.i("ADV#startScan");
            mScanning = true;
            BeaconRecordService.getInstance().clearData();
            beaconListAdapter.notifyDataSetChanged();

            mBluetoothAdapter.startLeScan(scanCallback);
            mScanHandler.postDelayed(scanTask, SCAN_PERIOD);
        } else {
            TelinkLog.i("ADV#stopScan");
            mScanning = false;
            mBluetoothAdapter.stopLeScan(scanCallback);
        }
        toolbar.setNavigationIcon(mScanning ? R.drawable.ic_stop : R.drawable.ic_refresh);
        pb_refreshing.setVisibility(mScanning ? View.VISIBLE : View.INVISIBLE);
    }


    @Override
    public void onStop() {
        super.onStop();
        if (mScanning && mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
            mBluetoothAdapter.stopLeScan(scanCallback);
        }
    }


    TextView tv_rssi;
    SeekBar sb_rssi;
    EditText et_name_address;

    private void showFilterDialog() {
        if (filterDialog == null) {
            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
            View view = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_beacon_filter, null);
            builder.setTitle("Scan Filter");
            builder.setView(view);
            builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.cancel();
                    onFilterUpdate();
                }
            }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.cancel();
                }
            });

            tv_rssi = view.findViewById(R.id.tv_rssi);
            sb_rssi = view.findViewById(R.id.sb_rssi);
//            sb_rssi.setProgress(-recordFilter.rssi);
//            tv_rssi.setText(getString(R.string.rssi_desc, recordFilter.rssi));
            sb_rssi.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
//                    recordFilter.rssi = -seekBar.getProgress();
                    tv_rssi.setText(getString(R.string.rssi_desc, -progress));
                }

                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
                }

                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
                    tv_rssi.setText(getString(R.string.rssi_desc, -seekBar.getProgress()));
                }
            });


            et_name_address = view.findViewById(R.id.et_name_address);
            builder.setCancelable(true);
            filterDialog = builder.create();
        }
        sb_rssi.setProgress(-recordFilter.rssi);
        tv_rssi.setText(getString(R.string.rssi_desc, recordFilter.rssi));
        et_name_address.setText(recordFilter.nameOrAddress);
        filterDialog.show();
    }

    private void updateFilterText() {
        String s;
        if (TextUtils.isEmpty(recordFilter.nameOrAddress)) {
            s = getString(R.string.record_filter_desc_rssi, recordFilter.rssi);
        } else {
            s = getString(R.string.record_filter_desc_all, recordFilter.rssi, recordFilter.nameOrAddress);
        }

        tv_filter.setText(s);
    }

    private void onFilterUpdate() {
        recordFilter.rssi = -sb_rssi.getProgress();
        recordFilter.nameOrAddress = et_name_address.getText().toString();
        TelinkLog.d("show waiting...");
        showWaitingDialog("applying...");
        mScanHandler.postDelayed((new Runnable() {
            @Override
            public void run() {
                TelinkLog.d("filter update: " + recordFilter.toString());
                updateFilterText();
                FileSystem.writeAsObject(getActivity(), FILTER_CACHE_NAME, recordFilter);
                BeaconRecordService.getInstance().updateFilter(recordFilter);
                TelinkLog.d("dismiss waiting...");
                dismissWaitingDialog();
            }
        }), 100);
    }

    private BluetoothAdapter.LeScanCallback scanCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
//            TelinkLog.w("scan:" + device.getName() + " mac:" + device.getAddress() + " rssi:" + rssi + " record:  " + Arrays.bytesToHexString(scanRecord, ":"));
//            if (!device.getAddress().toUpperCase().contains("FF:FF:BB:CC:DD")) return; // for dev
            if (device.getName()!=null){
                if (device.getName().contains("HZJ")){
                    BeaconRecordService.getInstance().pushRecord(new AdvertisingDevice(device, rssi, scanRecord));

                }
            }

        }
    };

    private Runnable scanTask = new Runnable() {
        @Override
        public void run() {
            if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
                scanToggle(false);
            }
        }
    };

    private String getAppVersion() {
        try {
            PackageManager manager = getActivity().getPackageManager();
            PackageInfo info = manager.getPackageInfo(getActivity().getPackageName(), 0);
            String version = info.versionName;
            return "V" + version;
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    @Override
    public void onRecordInsert(AdvertisingDevice advDevice, int position) {
        TelinkLog.d("onRecordInsert : " + position);
        beaconListAdapter.notifyItemInserted(position);
    }

    @Override
    public void onRecordUpdate(AdvertisingDevice device, int position) {
        TelinkLog.d("onRecordUpdate : " + position);
        beaconListAdapter.notifyItemChanged(position);
    }

    @Override
    public void onRefresh() {
        TelinkLog.d("onRefresh");
        beaconListAdapter.notifyDataSetChanged();
    }
}
